package org.infodavid.common.services;

import javax.persistence.PersistenceException;

import org.infodavid.common.IBuilder;
import org.infodavid.common.model.criteria.IExtendedSearchCriteria;
import org.infodavid.common.persistence.IDataObject;
import org.infodavid.common.services.exceptions.ServiceException;
import org.infodavid.common.services.validators.IValidator;

/**
 * The Class AbstractEntityService.
 * @param <L> the generic type
 * @param <T> The type of the entity
 * @param <C> The type of the search criteria
 */
public abstract class AbstractEntityService<L extends IDataObject<Long>,T extends L,C extends IExtendedSearchCriteria>
    extends AbstractService<ServiceException> implements IEntityService<L,T,C> {

	/**
	 * The Class InterceptorEventImpl.
	 */
	public static class InterceptorEventImpl implements IInterceptorEvent {

		/** The context. */
		private final IApplicationContext context;

		/** The service. */
		@SuppressWarnings("rawtypes")
		private final IEntityService service;

		/** The action. */
		private final String action;

		/** The arguments. */
		private final Object[] arguments;

		/** The results. */
		Object[] results = null;

		/**
		 * Instantiates a new interceptor event.
		 * @param ctx the context
		 * @param srv the service
		 * @param act the action
		 */
		@SuppressWarnings("rawtypes")
		public InterceptorEventImpl(final IApplicationContext ctx, final IEntityService srv,
		    final String act) {
			context = ctx;
			service = srv;
			action = act;
			arguments = null;
		}

		/**
		 * Instantiates a new interceptor event impl.
		 * @param ctx the context
		 * @param srv the service
		 * @param act the action
		 * @param args the arguments
		 */
		@SuppressWarnings("rawtypes")
		public InterceptorEventImpl(final IApplicationContext ctx, final IEntityService srv,
		    final String act, final Object... args) {
			context = ctx;
			service = srv;
			action = act;
			arguments = args;
		}

		/*
		 * (non-Javadoc)
		 * @see org.infodavid.common.services.IEntityService.IInterceptorEvent#getContext()
		 */
		public IApplicationContext getContext() {
			return context;
		}

		/*
		 * (non-Javadoc)
		 * @see org.infodavid.common.services.IEntityService.IInterceptorEvent#getInvoker()
		 */
		@SuppressWarnings("rawtypes")
		public IEntityService getInvoker() {
			return service;
		}

		/*
		 * (non-Javadoc)
		 * @see org.infodavid.common.services.IEntityService.IInterceptorEvent#getAction()
		 */
		public String getAction() {
			return action;
		}

		/*
		 * (non-Javadoc)
		 * @see org.infodavid.common.services.IEntityService.IInterceptorEvent#getArguments()
		 */
		public Object[] getArguments() {
			return arguments;
		}

		/*
		 * (non-Javadoc)
		 * @see org.infodavid.common.services.IEntityService.IInterceptorEvent#getResults()
		 */
		public Object[] getResults() {
			return results;
		}

		/*
		 * (non-Javadoc)
		 * @see
		 * org.infodavid.common.services.IEntityService.IInterceptorEvent#setResults(java.lang.Object[])
		 */
		public IInterceptorEvent setResults(final Object... values) {
			results = values;

			return this;
		}
	}

	/** The builder. */
	private final IBuilder<T> builder;

	/** The class of the entity. */
	private final Class<T> entityClass;

	/** The validator. */
	private IValidator<T> validator = null;

	/** The main interceptor. */
	private IInterceptor<T> interceptor = null;

	/**
	 * Instantiates a new service.
	 * @param pEntityClass the entity class
	 * @param pValidator the validator
	 * @param pBuilder the builder
	 */
	protected AbstractEntityService(final Class<T> pEntityClass, final IValidator<T> pValidator,
	    final IBuilder<T> pBuilder) {
		super();

		entityClass = pEntityClass;
		builder = pBuilder;
		validator = pValidator;
	}

	/**
	 * Creates the.
	 * @return a new instance
	 * @throws InstantiationException the instantiation exception
	 */
	public T create() throws InstantiationException {
		return builder.create();
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @return the validator
	 * @see org.infodavid.common.services.IEntityService#getValidator()
	 */
	public IValidator<T> getValidator() {
		return validator;
	}

	/**
	 * Sets the validator.
	 * @param value the validator
	 */
	protected void setValidator(final IValidator<T> value) {
		validator = value;
	}

	/**
	 * See super class or interface. (non-Javadoc)
	 * @return the interceptor
	 * @see org.infodavid.common.services.IEntityService#getInterceptor()
	 */
	public IInterceptor<T> getInterceptor() {
		return interceptor;
	}

	/**
	 * Sets the interceptor.
	 * @param value the new interceptor
	 */
	protected void setInterceptor(final IInterceptor<T> value) {
		interceptor = value;
	}

	/**
	 * Return the entityClass.
	 * @return the entityClass
	 */
	protected Class<T> getEntityClass() {
		return entityClass;
	}

	/**
	 * PostExecute.
	 * @param evt the evt
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	protected void postExecute(final IInterceptorEvent evt) throws PersistenceException,
	    ServiceException {
		IInterceptor<T> current = getInterceptor();

		while (current != null) {
			interceptor.postExecute(evt);
			current = current.getNext();
		}
	}

	/**
	 * PreExecute.
	 * @param context the context
	 * @param action the action
	 * @param arguments the arguments
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	protected IInterceptorEvent preExecute(final IApplicationContext context, final String action,
	    final Object... arguments) throws PersistenceException, ServiceException {
		final IInterceptorEvent evt = new InterceptorEventImpl(context, this, action, arguments);
		IInterceptor<T> current = getInterceptor();

		while (current != null) {
			interceptor.preExecute(evt);
			current = current.getNext();
		}

		return evt;
	}
}
